package MultithreadCase;




/*import java.util.Timer;
import java.util.TimerTask;

//标准库中的定时器
//标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule .
//schedule 包含两个参数. 第一个参数指定即将要执行的任务代码, 第二个参数指定多长时间之后执行 (单位为毫秒)
public class TimerScheduleTest {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {//new TimerTask是要实现的任务，源码可知这里是实现了Runable接口的
            @Override
            public void run() {
                System.out.println("3秒到了后实现hello");
            }
        }, 3000);
        System.out.println("先实现main");
    }
}
//实现完以上代码后，该线程并没有结束！是因为Timer内部有专门的线程来负责执行注册的任务，还要等待其他的任务加进来*/



import java.util.concurrent.PriorityBlockingQueue;

// 创建一个类, 表示一个任务.
class MyTask implements Comparable<MyTask> {//该任务是需要将时间短的放在队首，需要比较时间
    // 任务具体要干啥
    private Runnable runnable;
    // 任务具体啥时候干. 保存任务要执行的毫秒级时间戳
    private long time;

    // delay是绝对的时间戳的值，即执行时刻
    public MyTask(Runnable runnable, long delay) {
        this.runnable = runnable;
        this.time = System.currentTimeMillis() + delay;
    }

    public void run() {
        runnable.run();//运行该任务
    }

    public long getTime() {//获取到该任务设置的 执行时刻
        return time;
    }

    @Override
    public int compareTo(MyTask o) {
        //时间小的需要在队列前面
        return (int) (this.time - o.time);
    }
}

class MyTimer {
    // 定时器内部要能够存放多个任务--用带优先级的阻塞队列
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();

    public void schedule(Runnable runnable, long delay) {
        MyTask task = new MyTask(runnable, delay);
        queue.put(task);
        // 每次任务插入成功之后, 都唤醒一下扫描线程, 让线程重新检查一下队首的任务看是否时间到要执行~~
        synchronized (locker) {
            locker.notify();
        }
    }

    private Object locker = new Object();

    public MyTimer() {//在MyTimer类中设置一个扫描线程用来扫描队首任务，看看队首任务是否到达指定时间要去执行
        Thread t = new Thread(() -> {
            while (true) {
                try {
                    // 先取出队首元素
                    MyTask task = queue.take();
                    // 再比较一下看看当前这个任务时间到了没?
                    long curTime = System.currentTimeMillis();
                    if (curTime < task.getTime()) {
                        // 时间没到, 把任务再塞回到队列中.
                        queue.put(task);
                        // 由于while(true)执行的很快，就会一直获取当前时间和指定时间作比较，忙等比较浪费CPU资源。所以就给扫描线程指定一个等待时间
                        synchronized (locker) {
                            //为啥不用sleep：因为不能被中途唤醒！在等待的途中可能会有新的更前面的任务加入
                            locker.wait(task.getTime() - curTime);
                        }
                    } else {
                        // 时间到了, 执行这个任务
                        task.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }
}

public class TimerScheduleTest {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        //此时直插入一个任务，10秒后执行！扫描线程扫描到这个对首任务10秒后执行，就wait(当前时间+10秒)
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("10秒到了：执行 hello timer");
            }
        }, 10000);

        //但是此时又插入一个任务，三秒后就要执行，比最先插入的任务更早执行。所以就要唤醒扫描线程，来扫描新的队首任务，并做出新的wait
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("3秒到了：执行 hello timer");
            }
        },3000);

    }
}



